package main

import (
	"context"
	"crypto/tls"
	"encoding/json"
	"flag"
	"fmt"
	"golang.org/x/time/rate"
	"io"
	"math/rand"
	"net"
	"net/http"
	"strings"
	"sync"
	"time"
)

func PrintWithTimeLn(args ...interface{}) {
	currentTime := time.Now()
	formattedTime := currentTime.Format("2006-01-02 15:04:05")
	fmt.Printf("%s: ", formattedTime)
	fmt.Println(args...)
}

var ipStr []string
var speed int
var threads int

// 定义与JSON响应匹配的结构体
type Response struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
	Data    []struct {
		DownloadURL string `json:"download_url"`
	} `json:"data"`
}

// 定义与JSON响应匹配的结构体
type ResponseIp struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
	Data    []struct {
		IpStr string `json:"ip_str"`
	} `json:"data"`
}

// 请求接口获取代理IP
func getProxyIp() []string {
	url := "http://119.36.114.131:801/admin.php/getDownloadIps"
	/// 发起请求
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println("请求失败:", err)
		return nil
	}
	defer resp.Body.Close()

	// 读取响应
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("读取响应失败:", err)
		return nil
	}
	// 解析json
	var responseData ResponseIp
	err = json.Unmarshal(body, &responseData)
	if err != nil {
		fmt.Println("解析json失败:", err)
		return nil
	}

	// 初始化urlArray
	ipArray := make([]string, 0)

	// 提取download_url并添加到urlArray中
	for _, item := range responseData.Data {
		ipArray = append(ipArray, item.IpStr)
	}
	// 获取IP列表
	ipStr = ipArray
	return ipStr
}

func getapkurl() []string {
	url := "http://119.36.114.131:801/admin.php/getDownloadResources"
	// 发起请求
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println("请求失败:", err)
		return nil
	}
	defer resp.Body.Close()

	// 读取响应
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("读取响应失败:", err)
		return nil
	}

	// 解析json
	var responseData Response
	err = json.Unmarshal(body, &responseData)
	if err != nil {
		fmt.Println("解析json失败:", err)
		return nil
	}

	// 初始化urlArray
	urlArray := make([]string, 0)
	// 提取download_url并添加到urlArray中
	for _, item := range responseData.Data {
		urlArray = append(urlArray, item.DownloadURL)
	}

	return urlArray
}

func download(_url string, wg *sync.WaitGroup, semaphore chan struct{}, limiter *rate.Limiter) {
	defer wg.Done()
	semaphore <- struct{}{}
	defer func() { <-semaphore }()

	dialer := &net.Dialer{
		Timeout:   3 * time.Second,
		KeepAlive: 3 * time.Second,
	}
	client := &http.Client{
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{
				// 跳过证书验证
				InsecureSkipVerify: true,
			},
			DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
				if len(ipStr) == 0 {
					return nil, fmt.Errorf("no proxy IPs available")
				}
				splitStr := strings.Split(addr, ":")
				addr = ipStr[rand.Intn(len(ipStr))] + ":" + splitStr[1]
				return dialer.DialContext(ctx, network, addr)
			},
			MaxIdleConns:        100,
			MaxIdleConnsPerHost: 10,
			IdleConnTimeout:     90 * time.Second,
		},
	}

	req, err := http.NewRequest("GET", _url, nil)
	if err != nil {
		PrintWithTimeLn("Error creating request for:", _url, err)
		return
	}

	req.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36")
	req.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
	req.Header.Add("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
	req.Header.Add("Connection", "keep-alive")

	resp, err := client.Do(req)
	if err != nil {
		PrintWithTimeLn("Error fetching URL:", _url, err)
		return
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		PrintWithTimeLn("Unexpected status code", _url, resp.StatusCode)
		return
	}

	buffer := make([]byte, 32*1024) // 增大缓冲区大小

	
	for {
		n, err := resp.Body.Read(buffer)
		if err != nil {
			if err != io.EOF {
				PrintWithTimeLn("Error reading body:", _url, err)
			}
			break
		}
		if n == 0 {
			break
		}

		// 使用速率限制器
		limiter.WaitN(context.Background(), n)
	}
}


func main() {

	flag.IntVar(&speed, "speed", 1, "处理速度 Mb/s")
	flag.IntVar(&threads, "threads", 400, "线程数")
	// 解析命令行参数
	flag.Parse()

	limiter := rate.NewLimiter(rate.Limit(speed*1000*1024*1024/8), 32*1024) // 每次允许32KB的数据传输
	semaphore := make(chan struct{}, threads)                               // 控制并发数为链接数
	for {
		// 获取代理IP
		getProxyIp()
		// 获取下载链接
		urls := getapkurl()
		if urls == nil {
			fmt.Println("未获取到下载链接")
			return
		}
		var wg sync.WaitGroup
		for _, url := range urls {
			wg.Add(1)
			go download(url, &wg, semaphore, limiter)
		}
		//wg.Wait()
		//fmt.Println("所有下载任务完成")
	}
}

